//
//  XPGCD_Demo.swift
//  PPKit
//
//  Created by xiaopin on 2019/8/5.
//  Copyright © 2019 PPKit. All rights reserved.
//

import UIKit
/*
 使用前请学习一下多线程知识
 
 1、进程和线程
 进程：进程指在系统中能独立运行并作为资源分配的基本单位，它是由一组机器指令、数据和堆栈等组成的，是一个能独立运行的活动实体。
 线程：线程是进程的基本执行单元，一个进程（程序）的所有任务都在线程中执行。
 操作系统引入进程的目的：为了使多个程序能并发执行，以提高资源的利用率和系统的吞吐量。
 操作系统引入线程的目的：在操作系统中再引入线程，则是为了减少程序在并发执行时所付出的时空开销，使OS具有更好的并发性。多线程技术可以提高程序的执行效率。

 2.GCD概念
 Grand Central Dispatch(GCD) 是 Apple 开发的一个多核编程的较新的解决方法。它主要用于优化应用程序以支持多核处理器以及其他对称多处理系统。它是一个在线程池模式的基础上执行的并发任务。在 Mac OS X 10.6 雪豹中首次推出，也可在 iOS 4 及以上版本使用。

 3.为什么要用GCD? 简述优点
 因为 GCD 有很多好处啊，具体如下：
    * GCD 可用于多核的并行运算
    * GCD 会自动利用更多的 CPU 内核（比如双核、四核）
    * GCD 会自动管理线程的生命周期（创建线程、调度任务、销毁线程）
    * 程序员只需要告诉 GCD 想要执行什么任务，不需要编写任何线程管理代码

 4.任务和队列
    执行任务有两种：同步执行sync和异步执行async
    同步执行（sync）
    1.同步添加任务到指定的队列中，在添加的任务执行结束之前，会一直等待，直到队列里面的任务完成之后再继续执行。
    2.只能在当前线程中执行任务，不具备开启新线程的能力。
    异步执行（async）
    1.异步添加任务到指定的队列中，它不会做任何等待，可以继续执行任务。
    2.可以在新的线程中执行任务，具备开启新线程的能力。

    队列（Dispatch Queue）：这里的队列指执行任务的等待队列，即用来存放任务的队列。队列是一种特殊的线性表，采用FIFO（先进先出）的原则，即新任务总是被插入到队列的末尾，而读取任务的时候总是从队列的头部开始读取。每读取一个任务，则从队列中释放一个任务。
    * 串行队列（Serial Dispatch Queue）
        1.每次只有一个任务被执行。让任务一个接着一个地执行。（只开启一个线程，一个任务执行完毕后，再执行下一个任务）
    * 并发队列（Concurrent Dispatch Queue
        1.可以让多个任务并发（同时）执行。（可以开启多个线程，并且同时执行任务）
 5.GCD的基本使用
    GCD有两个全局的队列：全局串行队列DispatchQueue.main和全局并发队列DispatchQueue.gloabl()
    
 **/
class XPGCD_Demo: NSObject {
    
    #if DEBUG
    /// 示例代码
    func sampleCodes(){
        //GCD三种创建队列的方法
    
        //创建串行队列
        let serial = DispatchQueue(label: "serialQueue1")
        
        //创建并行队列
        let concurrent = DispatchQueue(label: "concurrentQueue1", attributes: .concurrent)
        
        //暂停一个队列
        concurrent.suspend()
        
        //继续队列
        concurrent.resume()
        /*
         (2）获取系统存在的全局队列
         Global Dispatch Queue有4个执行优先级：
         .userInitiated 高
         .default 正常
         .utility 低
         .background 非常低的优先级（这个优先级只用于不太关心完成时间的真正的后台任务）
         */
        let globalQueue = DispatchQueue.global(qos: .default)
        
        let gloabalQue = DispatchQueue.global()
        
        DispatchQueue(label: "queueName", qos: .default, attributes: .concurrent, autoreleaseFrequency: .inherit)
    }
    
    /// 全局串行队列代码示例
    func mainQueueCode(){
        //同步sync, 异步async
        //方式1
        DispatchQueue.main.async {
            //在全局串行队列中执行的代码
        }
        
        //方式2
        //DispatchQueue.main.async(execute: DispatchWorkItem)
        
        //方式3
        //DispatchQueue.main.async(group: <#T##DispatchGroup#>, execute: <#T##DispatchWorkItem#>)
        
        //方式4
        //DispatchQueue.main.async(group: <#T##DispatchGroup?#>, qos: <#T##DispatchQoS#>, flags: <#T##DispatchWorkItemFlags#>, execute: <#T##() -> Void#>)
    }
    
    /// 全局并行队列代码示例
    func globalQueueCode(){
        //同步sync, 异步async
    
        //方式1
        DispatchQueue.global().async {
            //在全局串行队列中执行的代码
        }
        
        //方式2
        //DispatchQueue.global().async(execute: DispatchWorkItem)
        
        //方式3
        //DispatchQueue.global().async(group: <#T##DispatchGroup#>, execute: <#T##DispatchWorkItem#>)
        
        //方式4
        //DispatchQueue.global().async(group: <#T##DispatchGroup?#>, qos: <#T##DispatchQoS#>, flags: <#T##DispatchWorkItemFlags#>, execute: <#T##() -> Void#>)
    }
    
    /// 延时执行
    func afterCode(){
        DispatchQueue.global().asyncAfter(deadline: DispatchTime.now() + 2) {
            //延迟2执行
        }
    }
    
    /// 多任务执行示例代码
    func mutableRequestCodes(){
        /*
         代码块：xpgcd_semaphore_multiple_async
         在执行多个异步任务的时候需要使用这种中方式去编写
         */
        //创建并列任务队列
        let queue = DispatchQueue(label: "com.xiaopin.semaphore.queue", qos: .default, attributes: .concurrent)
        //分组
        let group = DispatchGroup()
        weak var weakSelf = self
        
        queue.async(group: group) {
            //创建信号量
            let sema = DispatchSemaphore(value: 0)
            //执行异步操作，完成后sema.signal()
            //异步操作代码
            
            //异步调用返回前，就会一直阻塞在这
            sema.wait()
        }
        
        queue.async(group: group) {
            //创建信号量
            let sema = DispatchSemaphore(value: 0)
            //执行异步操作，完成后sema.signal()
            //异步操作代码
            
            //异步调用返回前，就会一直阻塞在这
            sema.wait()
        }
        
        //全部调用完成后回到主线程,再更新UI
        group.notify(queue: DispatchQueue.main, execute: {[weak self] in
            //tableView同时用到了两个请求到返回结果
            //多个异步操作执行完以后的操作
        })
    }
    #endif
}
